package com.itfreer.gis.data.server.geoserver;

import java.util.ArrayList;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.locationtech.jts.geom.Polygon;
import org.opengis.feature.simple.SimpleFeature;

import com.itfreer.gis.data.server.GisHttpUtil;
import com.itfreer.gis.data.server.SearchPara;

/**
 * Gerserver wfs查询
 *
 * @author cai 特别注意:Geoserve服务空间关系查询时,经纬度坐标表示顺序反过来
 */
public class GeoserverWFSSearch {

    /**
     * 空间查询，与当关要素空间叠加关系查询
     *
     * @param type     地图类型
     * @param url      地址
     * @param geometry 空间要素
     * @param paras    参数
     * @return
     */
    public List<SimpleFeature> queryFeature(String url, Geometry geometry, SearchPara paras) throws Exception {

        // geometry 需要传入反过来的坐标串,需要做下处理
        String geometryStr = "";

        // 版本从1.1.0版本开始，坐标串经纬度表示需要反过来,
        Object version = paras.getVersion();
        if (version != null && (version.equals("1.1.0") || version.equals("2.0.0"))) {
            geometryStr = this.inverseGemotry(geometry);
        } else {
            geometryStr = geometry.toString();
        }

        String geo_field = paras.getGeoField();
        if (geo_field == null || geo_field.equals("")) {
            geo_field = GeoServerConstants.GEO_FIELD;
        }

        String sumFilter = "";

        String filter = paras.getFilter();
        if (null != filter && !"".equals(filter)) {
            sumFilter = filter;
        }
        if (null != geometryStr && !"".equals(geometryStr)) {
            if (null != sumFilter && !"".equals(sumFilter)) {
                sumFilter += " AND INTERSECTS(" + geo_field + "," + geometryStr + ")";
            } else {
                sumFilter = "INTERSECTS(" + geo_field + "," + geometryStr + ")";
            }
        }

        return queryFeatureEx(url, paras, sumFilter);
    }

    /**
     * 空间查询，查询当前地图范围内地要素
     *
     * @param type   地图类型
     * @param url    地址
     * @param extent 当前地图范围
     * @param paras  参数
     * @return
     */
    public List<SimpleFeature> queryFeature(String url, String extent, SearchPara paras) throws Exception {

        String geo_field = paras.getGeoField();
        if (geo_field == null || geo_field.equals("")) {
            geo_field = GeoServerConstants.GEO_FIELD;
        }

        String filter = "";
        if (extent != null && !extent.equals("")) {
            filter += "BBOX(" + geo_field.toString() + "," + extent + ")";
        }
        return queryFeatureEx(url, paras, filter);
    }

    /**
     * 属性查询，根据属性条件进行查询
     *
     * @param type   地图类型
     * @param url    地址
     * @param where  属性条件
     * @param extent 当前地图范围
     * @param paras  参数
     * @return
     */
    public List<SimpleFeature> queryFeature(String url, String where, String extent, SearchPara paras)
            throws Exception {

        String geo_field = paras.getGeoField();
        if (geo_field == null || geo_field.equals("")) {
            geo_field = GeoServerConstants.GEO_FIELD;
        }

        if (where == null || "".equals(where)) {
            return null;
        }

        String filter = where;
        if (extent != null && !extent.equals("")) {
            filter += " AND BBOX(" + geo_field.toString() + "," + extent + ")";
        }

        return queryFeatureEx(url, paras, filter);
    }

    /***
     * 空间分析
     *
     * @param source geometry字符串
     * @return List<SimpleFeature>
     */
    private List<SimpleFeature> queryFeatureEx(String url, SearchPara paras, String filter) {

        if (url == null || url.equals("")) {
            return null;
        }

        String serviceName = paras.getServiceName();
        if (serviceName == null || serviceName.equals("")) {
            return null;
        }

        // 版本从1.1.0版本开始，坐标串经纬度表示需要反过来,
        String version = paras.getVersion();
        if (version == null || version.equals("")) {
            version = GeoServerConstants.SERVE_VERSION;
        }

        String srsName = paras.getSrs();
        if (srsName == null || srsName.equals("")) {
            srsName = GeoServerConstants.SERVE_SRS;
        }

        List<NameValuePair> params = new ArrayList<>();
        // 参数组装
        params.add(new BasicNameValuePair("service", GeoServerConstants.SERVE_TYPE));
        params.add(new BasicNameValuePair("version", version));
        params.add(new BasicNameValuePair("request", GeoServerConstants.SERVE_REQUEST));
        params.add(new BasicNameValuePair("typeName", serviceName));
        params.add(new BasicNameValuePair("outputformat", GeoServerConstants.FORMAT));
        params.add(new BasicNameValuePair("srsName", srsName));

        if (filter != null && !filter.equals("")) {
            params.add(new BasicNameValuePair("cql_filter", filter));
        }

        return GisHttpUtil.post(url, params);
    }

    /***
     * 坐标串取反操作
     *
     * @param geometry
     * @return
     */
    private String inverseGemotry(Geometry geometry) {
        // 获取坐标串
        Coordinate[] coordinates = GeoServeUtils.inverse(geometry);
        if (geometry instanceof Point) {
            return GeoServeUtils.createPoint(coordinates).toString();
        }

        if (geometry instanceof LineString) {
            return GeoServeUtils.createLine(coordinates).toString();
        }

        if (geometry instanceof Polygon) {
            return GeoServeUtils.createPolygon(coordinates).toString();
        }

        throw new IllegalArgumentException("Unable to inverse " + geometry);
    }
}
